#ifdef PLC_IS_APP
#include "plc_abi.h"
#else

#include <Arduino.h>

#endif
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
enum {
    COMM_STATUS_SERIAL_OPEN, //
    COMM_STATUS_OK,
    COMM_STATUS_TIMEOUT,
    COMM_STATUS_CRC_ERR,
    COMM_STATUS_UNKNOWN_ERROR,
    STATUS_CASH_FULL,
    COMM_STATUS_ILL_CMD,
    COMM_STATUS_WEIGHT_IS_ZERO,
    COMM_SATUS_SET_ZERO,
    COMM_STATUS_IDLE,
    COMM_STATUS_RECEIVE
};
enum {
    COMM_FLAG_DUPLTEX,   //˫��ģʽ,����
    COMM_FLAG_DECODE_ALL //ͳһ����,���н���Э��ͳһ����
};

///@brief :
#define COMM_STATUS_SET(sta, x) sta |= 1 << x
///@brief :
#define COMM_STATUS_CLEAR(sta, x) sta &= ~(1 << x)
///@brief :
#define COMM_STATUS(sta, x) (sta & (1 << x))

typedef struct {
    u8 *buf;
    u8 *rinx;
    u8 *winx;
    u16 size;
} buf_data;

buf_data *buf_data_init(buf_data *dat, u8 *buf, u16 size);

int buf_data_len(buf_data *dat);

int buf_data_put(buf_data *dat, const u8 *buf, u8 len);

void buf_data_clear(buf_data *dat);

int buf_data_read(buf_data *dat, u8 *dest, u16 len);

int buf_data_put_char(buf_data *dat, u8 buf);

typedef enum {
    PROTOCOL_ELEMENT_HEAD, //,,
    PROTOCOL_ELEMENT_LEN,
    PROTOCOL_ELEMENT_FIXED, //
    PROTOCOL_ELEMENT_DATA,  //,
    PROTOCOL_ELEMENT_CHECK  //
} element_type;

typedef struct _protocol protocol_t;
typedef struct _protocol_dev protocol_dev_t;
typedef struct _protocol_element protocol_element_t;

struct _protocol_dev {
    u32 send_flag;
    int error;
    u8 next, query_nrs, write_nrs;
    void *serial;

    int (*encode)(protocol_dev_t *dev, protocol_t *prl, protocol_element_t **, u8 elen);

    int (*decode)(protocol_dev_t *dev, protocol_t *prl, protocol_element_t **, u8 elen);

    int (*receive)(protocol_dev_t *dev, protocol_t *);    //Э����մ���
    int (*test_cb)(protocol_dev_t *dev, protocol_t *prl); //�����ú���,Э�鷢��ǰ����
    void (*dataChanged)(int prl, int param, int val);

    protocol_t *rx; //���յ�Э��,��Ϊreceive�Ĳ���
    protocol_t **write_array;
    protocol_t **query_array;

    //! @brief ���ͷ�ʽ
    //! ���з���query_array
    //! ��������,��Ҫ���з��Ϳ���,�Ŷ�
    //! MODE1:write_array,��дЭ�����ݺ�����send_flag
    //! MODE2:����senderָ��Ҫ���͵�Э��
    //! MODE3:���Э������,ָ��tx
    protocol_t *sender;   //������Э��ָ�� ,�ύ�����Ͷ��д�����
    buf_data *tx;         //�����͵����ݻ����� , �ȱ���,�������ύ����
    protocol_t *lastsend; //����͵�Э��,��Э����ղ���
};

struct _protocol_element {
    u8 len;

    int (*encode)(protocol_dev_t *dev, protocol_t *, protocol_element_t *);

    int (*decode)(protocol_dev_t *dev, protocol_t *, protocol_element_t *, u8 *buf);

    int (*check)(protocol_dev_t *dev, protocol_t *, protocol_element_t *);

    const u8 *context;
};

typedef struct {
    protocol_element_t base;
    u8 start, end;
} protocol_len_t;

typedef struct {
    protocol_element_t base;
    u8 start_byte;
} protocol_var_t;
typedef struct {
    protocol_element_t base;
    u8 start_byte;
} protocol_chksum_t;
struct _protocol {
    u16 cmd;
    u8 nrs;                    //Э��Ԫ������
    protocol_element_t **elts; //    Э��Ԫ������
    protocol_t *rsp;           // Ӧ��Э��
    u8 data_len;
    void *context;
};

class protocol {
public:
    virtual int init(u8 ch) {
        serialNo = ch;
        return 0;
    }

    int select(u32 timeout);

    int read_head(u8 len, const u8 *context, u32 timeout);

    int read_cmp_context(u8 len, const u8 *context, u32 timeout);

    int read_context(u8 len, const u8 *context, u32 timeout);

    int read_until(const u8 *context, u8 conetxt_len, u32 timeout);

    int fill_byte(protocol_dev_t *dev, protocol_t *prl, protocol_element_t *elt);

    int get_byte(protocol_dev_t *dev, protocol_t *prl, protocol_element_t *elt, u8 *buf);

    int fill_byte_parent(protocol_dev_t *dev, protocol_t *prl, protocol_element_t *elt);

    int checksum_8(protocol_dev_t *dev, protocol_t *prl, protocol_element_t *elt);

    int read_cmp_checksum_8(protocol_dev_t *dev, protocol_t *prl, protocol_element_t *elt);

    int checksum_8_0xff(protocol_dev_t *dev, protocol_t *prl, protocol_element_t *elt);

    int read_cmp_checksum_8_0xff(protocol_dev_t *dev, protocol_t *prl, protocol_element_t *elt);

    int protocol_decode(protocol_dev_t *dev, protocol_t *prl, protocol_element_t **, u8 elen);

    int protocol_encode(protocol_dev_t *dev, protocol_t *prl, protocol_element_t **, u8 elen);

    int protocol_poll(protocol_dev_t *dev);

    int protocol_receive(protocol_dev_t *dev, protocol_t *prl);

    int protocol_send(protocol_dev_t *dev, protocol_t *prl);     //ֱ�ӷ���һ��Э��
    int protocol_send_set(protocol_dev_t *dev, protocol_t *prl); //!����Э��ķ��ͱ�־,�ɶ��з���
    protocol_dev_t *protocol_dev_init(protocol_dev_t *dev);

    u8 calc_xor(u8 *buf, u8 len);

    u8 calc_checsum(u8 *buf, u8 len);

    int protocol_run(protocol_dev_t *dev, protocol_t *prl);

    int elt_read_context(protocol_dev_t *dev, protocol_t *prl, protocol_element_t *elt);

    int elt_read_len(protocol_dev_t *dev, protocol_t *prl, protocol_element_t *elt);

    int elt_read_data(protocol_dev_t *dev, protocol_t *prl, protocol_element_t *elt);

    int elt_read_cmp_context(protocol_dev_t *dev, protocol_t *prl, protocol_element_t *elt);

    int elt_read_head(protocol_dev_t *dev, protocol_t *prl, protocol_element_t *elt);

    buf_data rx_buf, tx_buf;
    u32 status, flag, interval;
    u8 serialNo;
};

